﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Linq;

namespace Apollo.Core
{
    public class FormGroup
    {
        public FormGroup() {
            this.Items = new List<FormItem>();
            this.SubGroups = new List<FormGroup>();
        }

        public string DisplayName { get; set; }

        public FormGroupType Type { get; set; }


        public EntityProperty ReverseProperty { get; set; }

        public EntityView View { get; set; }

        public string AspxControlSrc { get; set; }

        public string IFrameUrl { get; set; }

        public IList<FormItem> Items { get; set; }

        public IList<FormGroup> SubGroups { get; set; }



        public Form Form { get; set; }

        public FormGroup Parent { get; set; }


        public void SetFormType(FormItemType type)
        {
            if (this.SubGroups != null)
                foreach (FormGroup group in this.SubGroups)
                    group.SetFormType(type);

            if (this.Items != null)
                foreach (FormItem item in this.Items)
                    item.Type = type;

        }

        public XElement ToXml() {
            XElement xelem = new XElement("group");
            xelem.Add(new XAttribute("type", this.Type.ToString()));
            xelem.Add(new XAttribute("displayname", this.DisplayName));

            switch (this.Type) { 
                case FormGroupType.Properties:
                    foreach (FormItem item in this.Items)
                        xelem.Add(item.ToXml());
                    break;
                case FormGroupType.View:
                    xelem.SetValue(this.View.Id);
                    break;
                case FormGroupType.Aspx:
                    xelem.SetValue(this.AspxControlSrc);
                    break;
                case FormGroupType.IFrame:
                    xelem.SetValue(this.IFrameUrl);
                    break;
                case FormGroupType.Tab:
                    foreach (FormGroup subgroup in this.SubGroups)
                        xelem.Add(subgroup.ToXml());
                    break;
                case FormGroupType.ReverseProperty:
                    xelem.SetValue(this.ReverseProperty.Entity.Name + "." + this.ReverseProperty.PropertyName);

                    if (this.View != null) 
                        xelem.Add(new XAttribute("customview", View.Id));
                    
                    break;
            }
            
            return xelem;
        }

        public static FormGroup FromXml(XElement xelement, Form form) {
            FormGroup group = new FormGroup();

            group.Form = form;

            if (xelement.Name != "group")
                throw new ArgumentException("Invalid XML format! Expected name 'group', but got '" + xelement.Name + "'");

            if (xelement.Attribute("type") == null)
                throw new ArgumentException("Invalid XML format! Missing required attribute 'type'");

            group.Type = (FormGroupType)System.Enum.Parse(typeof(FormGroupType), xelement.Attribute("type").Value);
            group.DisplayName = xelement.Attribute("displayname").Value;

            switch (group.Type)
            {
                case FormGroupType.Properties:
                    foreach (XElement subElement in xelement.Elements("property"))
                        group.Items.Add(FormItem.FromXml(subElement, group));
                    break;
                case FormGroupType.View:
                    int viewId = int.Parse(xelement.Value);
                    group.View = Application.Meta<EntityView>().SingleOrDefault<EntityView>(ev => ev.Id == viewId);
                    break;
                case FormGroupType.Aspx:
                    group.AspxControlSrc = xelement.Value;
                    break;
                case FormGroupType.IFrame:
                    group.IFrameUrl = xelement.Value;
                    break;
                case FormGroupType.Tab:
                    foreach (XElement subGroup in xelement.Elements("group"))
                        group.SubGroups.Add(FormGroup.FromXml(subGroup, group));
                    break;
                case FormGroupType.ReverseProperty:
                    string[] reverseProperty = xelement.Value.Split(".".ToCharArray(), StringSplitOptions.RemoveEmptyEntries);
                    group.ReverseProperty = Application.Meta<EntityProperty>()
                        .SingleOrDefault<EntityProperty>(ep => ep.Entity.Name == reverseProperty[0] && ep.PropertyName == reverseProperty[1]);

                    if (xelement.Attribute("customview") != null) {
                        int customViewId = int.Parse(xelement.Attribute("customview").Value);
                        group.View = Application.Meta<EntityView>().SingleOrDefault<EntityView>(ev => ev.Id == customViewId);
                    }
                    break;
            }

            return group;
        }

        public static FormGroup FromXml(XElement xelement, FormGroup group)
        {
            FormGroup subgroup = FromXml(xelement, group.Form);
            
            subgroup.Parent = group;

            return subgroup;
        }
    }

    public enum FormGroupType { 
        Properties = 0,
        View = 1,
        Aspx = 2,
        Tab = 3,
        IFrame = 4,
        ReverseProperty = 5
    }
}
